/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.rest.config;

import ch.qos.logback.classic.Level;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.multicontext.annotation.BeanCollector;
import io.iec.edp.caf.rest.RESTEndpoint;
import io.iec.edp.caf.rest.RESTEndpointRegistrar;
import io.iec.edp.caf.rest.RESTServiceRegistrar;
import io.iec.edp.caf.rest.api.event.RestExceptionPublisher;
import io.iec.edp.caf.rest.filter.ServiceNotFoundFilter;
import io.iec.edp.caf.rest.server.event.RestStartupCompletedListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.Server;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author yisiqi
 * @since 1.0.0
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(RESTEndpoint.class)
public class RESTServerAutoConfiguration {

    /**
     * 懒加载模式下，通过启动后事件注册
     * :false表示默认值
     */
    @Bean
    @ConditionalOnExpression("${spring.main.lazy-initialization:false}")
    @Lazy(false)
    public ApplicationListener restStartupListener(Bus bus) {
        return new RestStartupCompletedListener(bus);
    }

    @Bean
    ServiceNotFoundFilter serviceNotFoundFilter(){
        return new ServiceNotFoundFilter();
    }

    /**
     * 非懒加载模式下，启动时通过bean注册
     */
    @Bean
    @BeanCollector
    @ConditionalOnBean(RESTEndpoint.class)
    @ConditionalOnMissingBean(name = "defaultRestServer")
    public List<Server> defaultRestServer(
            Bus bus,
            List<RESTEndpoint> endpoints
    ) throws InterruptedException {
        RESTServiceRegistrar restServiceRegistrar = RESTServiceRegistrar.getSingleton();
        restServiceRegistrar.finishRegistry();
        List<RESTEndpoint> endpointsCopy = new ArrayList<>(endpoints);
        endpoints.addAll(restServiceRegistrar.getEndpoints());
        restServiceRegistrar.putEndpoints(endpointsCopy);
        ExecutorService logThread = new ThreadPoolExecutor(1,1,0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        logThread.execute(()->{
            CountDownLatch countDownLatch = new CountDownLatch(endpoints.size());

            ExecutorService executor = new ThreadPoolExecutor(64, 64,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());
            for (RESTEndpoint endpoint : endpoints) {
                executor.execute(() -> {
//                RESTEndpointUtil.createJAXRSServer(endpoint.getPath(), bus, endpoint.getServices());
                    restServiceRegistrar.publishRestEndpoint(endpoint);
                    countDownLatch.countDown();
                });
            }
            executor.shutdown();

            try {
                countDownLatch.await();
                ServiceNotFoundFilter.finishRegistered();
            } catch (InterruptedException e) {
                log.error(e.getMessage(),e);
            }
            logRest();
        });
        logThread.shutdown();

        return null;
    }

    @Bean
    @Lazy(false)
    public RESTEndpointRegistrar lazyRESTEndpointRegistrar(Bus bus) {
        return new RESTEndpointRegistrar(bus);
    }


    @Bean
    public RestExceptionPublisher restExceptionPublisher(ApplicationEventPublisher eventPublisher) {
        return new RestExceptionPublisher(eventPublisher);
    }

    private void logRest(){
        String info = "All rest endpoints have already been registered. Now running on: "+CafEnvironment.getPort();
        Boolean enableConsoleLog = CafEnvironment.getEnvironment().getProperty("ENABLE_CONSOLE_LOGGING",Boolean.class,true);
        //如果不允许写info日志，则强制打开并输出
        if (!log.isInfoEnabled()) {
            ch.qos.logback.classic.LoggerContext loggerContext = (ch.qos.logback.classic.LoggerContext) LoggerFactory.getILoggerFactory();
            ch.qos.logback.classic.Logger loggerInLog4back = loggerContext.getLogger(RESTServerAutoConfiguration.class);
            Level originLevel = loggerInLog4back.getLevel();
            // 按传递的包名或类名修改日志级别。
            loggerInLog4back.setLevel(Level.INFO);
            loggerInLog4back.info(info);
            loggerInLog4back.setLevel(originLevel);
        } else {
            log.info(info);
        }

        //如果禁止输出控制台日志，则直接输出一下
        if (!enableConsoleLog) {
            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ");
            System.out.println(f.format(new Date()) + info);
        }
    }
}
